'''
Created on 06/06/2012

@author: Administrador
'''
import unittest
from main.memory import PhysicalMemory,MMU_ContinuousAssignment,Disk,BestAdjustment
from main.process import PCB, Instruction, Process, ProcessStatus,IOInstruction
from main.cpu import CPU
from main.dataStructures import ProcessesQueue
from main.ioDevs import IO

class TestMemory(unittest.TestCase):
    def setUp(self):
        self.memoria = PhysicalMemory(5,BestAdjustment())
        self.mmu = MMU_ContinuousAssignment()
        self.pcb1 =  PCB(3)
        self.pcb2 =  PCB(6)
        self.instruction1 =  IOInstruction(4,'Printer')
        self.instruction2 =  Instruction(ProcessStatus().IO,2)
        self.instruction3 =  Instruction(ProcessStatus().IO,3)
        self.instruction4 =  IOInstruction(4,'Printer')
        self.instruction5 =  Instruction(ProcessStatus().IO,5)
        self.instruction6 =  Instruction(ProcessStatus().IO,2)
        self.instruction7 =  Instruction(ProcessStatus().IO,7)
        self.process1 = Process(self.pcb1)
        self.process1.addInstruction(self.instruction1)
        self.process1.addInstruction(self.instruction2)
        self.process1.addInstruction(self.instruction3)
        self.process1.addInstruction(self.instruction4)
        #Proceso2/ preparado para hacer el calculo con la MMU_ContinuousAssignment
        self.process2 = Process(self.pcb2)
        self.process2.addInstruction(self.instruction5)
        self.process2.addInstruction(self.instruction6)
        self.process2.addInstruction(self.instruction7)
        self.cpu = CPU(ProcessesQueue(),IO(),self.mmu,self.memoria)
        self.process3 = Process(PCB(3))
        self.process4 = Process(PCB(4))
        self.processInCpu = Process(PCB(5))
        self.processSwaping = Process(PCB(6))
        self.disk = Disk()
        
        #----------------------------------------------
        
    def test_Constructor(self):
        self.assertTrue(len(self.memoria.cells)== 5)
    
    def test_TieneEspacio(self):
        self.memoria.cells[0] = self.instruction1
        self.memoria.cells[1] = self.instruction2
        self.memoria.cells[2] = self.instruction3
        #Memoria con 2 espacios libres
        self.assertTrue(self.memoria.hasSpace(2))
    
    def test_NoTieneEspacio(self):
        self.memoria.cells[0] = self.instruction1
        self.memoria.cells[2] = self.instruction2
        self.memoria.cells[4] = self.instruction3
        #Memoria con 2 espacios libres pero distribuidos
        self.assertFalse(self.memoria.hasSpace(2))


    def test_IndexWithSpaces(self):
        expected = [(2,2)]#(index,spaces)
        self.memoria.cells[0] = self.instruction1
        self.memoria.cells[1] = self.instruction2
        self.memoria.cells[4] = self.instruction3
        #Memoria con 2 espacios libres
        x = self.memoria.indexWithSpaces()
        self.assertTrue(x == expected)
        
    def test_IndexWithSpaces_Distribuido(self):
        expected = [(1,1),(3,1)]#(index,spaces)
        self.memoria.cells[0] = self.instruction1
        self.memoria.cells[2] = self.instruction2
        self.memoria.cells[4] = self.instruction3
        #Memoria con 2 espacios libres pero distribuidos
        x = self.memoria.indexWithSpaces()
        self.assertTrue(x == expected)
        
    def test_MMUwhenTransformsALogicDirInAPhysicalDir(self):
        self.process2.pcb.baseRegister = 2 
        self.process2.pcb.limitRegister = 4
        self.process2.pcb.currentInstruction = self.instruction7 #CurrentInstrction es instruction7 la que deberia ir a buscar a memoria
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction5#Proceso 2
        self.memoria.cells[3]= self.instruction6#Proceso 2
        self.memoria.cells[4]= self.instruction7#Proceso 2
        i = self.mmu.searchProgram(self.process2,self.memoria)#Me devuelve la instruccion en memoria
        self.assertTrue(i == self.instruction7)
        
    def test_whenAonlySpaceIsInMemoryAndMakesItNotCompacted(self):#Cuando hay un unico espacio en memoria y debo saber si esta entre medio de celdas llenas
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction3
#       self.memoria.cells[3]= self.instruction4
#       self.memoria.cells[4]= self.instruction5
        self.assertFalse(self.memoria.isInMiddle((3,2)))
        
        
    def test_isAMemoryCompacted_anySpace(self):#Una memoria sin espacio esta compactada
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction3
        self.memoria.cells[3]= self.instruction4
        self.memoria.cells[4]= self.instruction5
        self.assertTrue(self.memoria.isCompacted(self.memoria.indexWithSpaces()))
        
    def test_isAMemoryCompacted_oneSpaceAtLast(self):#Una memoria con un solo espacio al final esta compactada
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction3
        self.assertTrue(self.memoria.isCompacted(self.memoria.indexWithSpaces()))
    
    def test_isAMemoryCompacted_moreThanOneSpace(self):#Una memoria con mas de un espacio no es compacta
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[3]= self.instruction4
        self.assertFalse(self.memoria.isCompacted(self.memoria.indexWithSpaces()))
        
    def test_MoveABlock(self):
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
#        self.memoria.cells[2]= self.instruction3
        self.memoria.cells[3]= self.instruction4
        self.memoria.cells[4]= self.instruction5
        self.processY = Process(PCB(3))
        self.processY.addInstruction(self.instruction4)
        self.processY.addInstruction(self.instruction5)
        self.memoria.processesTable.append(self.processY)
        expected = {0:self.instruction1 , 1:self.instruction2, 2:self.instruction4, 3:self.instruction5, 4:None}
        self.memoria.moveBlock(2, self.memoria.indexWithSpaces())
        self.assertEquals(expected, self.memoria.cells)
    
    def test_compact(self):
        self.memoria.cells[0]= self.instruction1
#        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction3
#        self.memoria.cells[3]= self.instruction4
        self.memoria.cells[4]= self.instruction5
        expected = {0:self.instruction1 , 1:self.instruction3, 2:self.instruction5, 3:None , 4:None}
        self.processX = Process(PCB(3))
        self.processX.addInstruction(self.instruction3)
        self.memoria.processesTable.append(self.processX)
        self.processY = Process(PCB(3))
        self.processY.addInstruction(self.instruction5)
        self.memoria.processesTable.append(self.processY)
        self.memoria.compact()
        self.assertEquals(self.memoria.cells , expected)
        
    def test_quitAprocessOfMemory(self):
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        self.memoria.cells[2]= self.instruction5
        self.memoria.cells[3]= self.instruction6
        self.memoria.cells[4]= self.instruction7
        self.process2.pcb.baseRegister = 2
        self.process2.pcb.limitRegister = 4
        self.memoria.processesTable.append(self.process2)
        self.memoria.quitProcessOfMemory(self.process2)
        e = {0:self.instruction1, 1:self.instruction2, 2:None, 3:None, 4:None}
        self.assertEquals(e , self.memoria.cells)
        
    def test_swapping(self):
        self.memoria.cells[0]= self.instruction1
        self.memoria.cells[1]= self.instruction2
        #Process3
        self.memoria.cells[2]= self.instruction3
        self.memoria.cells[3]= self.instruction4
        #Process in cpu
        self.memoria.cells[4]= self.instruction5
        #Process4 
        #
        self.process3.addInstruction(self.instruction1)
        self.process3.addInstruction(self.instruction2)
        self.process3.pcb.baseRegister = 0
        #
        self.process4.addInstruction(self.instruction5)
        self.process4.pcb.baseRegister = 4
        #
        self.processInCpu.addInstruction(self.instruction3)
        self.processInCpu.addInstruction(self.instruction4)
        self.processInCpu.pcb.baseRegister = 2
        #
        self.processSwaping.addInstruction(self.instruction6)
        #
        self.cpu.currentProcess = self.processInCpu
        self.cpu.readyProcessesQueue.append(self.process3)
        self.cpu.readyProcessesQueue.append(self.process4)
        #
        self.memoria.processesTable.append(self.process3)
        self.memoria.processesTable.append(self.process4)
        self.memoria.processesTable.append(self.processInCpu)
        self.memoria.swap(self.processSwaping, self.disk,self.cpu)
        e = {0:self.instruction1, 1:self.instruction2, 2:self.instruction3, 3:self.instruction4, 4:self.instruction5}
        #
        self.assertEquals(self.memoria.cells[4], self.instruction5)
        self.assertTrue(self.memoria.processesTable.popTheLast() == self.processSwaping)
        
        
        
suite = unittest.TestLoader().loadTestsFromTestCase(TestMemory)
unittest.TextTestRunner(verbosity=2).run(suite)